/****************************************************************************
 **
 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
 ** This file is part of the examples of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
 ** Commercial Usage
 ** Licensees holding valid Qt Commercial licenses may use this file in
 ** accordance with the Qt Commercial License Agreement provided with the
 ** Software or, alternatively, in accordance with the terms contained in
 ** a written agreement between you and Nokia.
 **
 ** GNU Lesser General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU Lesser
 ** General Public License version 2.1 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.LGPL included in the
 ** packaging of this file.  Please review the following information to
 ** ensure the GNU Lesser General Public License version 2.1 requirements
 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
 ** rights.  These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
 ** GNU General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU
 ** General Public License version 3.0 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.  Please review the following information to
 ** ensure the GNU General Public License version 3.0 requirements will be
 ** met: http://www.gnu.org/copyleft/gpl.html.
 **
 ** If you have questions regarding the use of this file, please contact
 ** Nokia at qt-info@nokia.com.
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

#include <QtGui>

#include "highlighter.h"

Highlighter::Highlighter(QTextDocument *parent)
  : QSyntaxHighlighter(parent) {
  HighlightingRule rule;
  keywordFormat.setForeground(Qt::darkBlue);
  keywordFormat.setFontWeight(QFont::Bold);
  QStringList keywordPatterns;
  keywordPatterns     << "\\bbreak\\b" << "\\bdefault\\b" << "\\bfunc\\b"
                      << "\\binterface\\b" << "\\bselect\\b" << "\\bcase\\b"
                      << "\\bdefer\\b" << "\\bgo\\b" << "\\bmap\\b"
                      << "\\bstruct\\b" << "\\bchan\\b" << "\\belse\\b"
                      << "\\bgoto\\b" << "\\bpackage\\b" << "\\bswitch\\b"
                      << "\\bconst\\b" << "\\bfallthrough\\b" << "\\bif\\b"
                      << "\\brange\\b" << "\\btype\\b" << "\\bcontinue\\b"
                      << "\\bfor\\b" << "\\bimport\\b" << "\\breturn\\b"
                      << "\\bvar\\b" << "\\buint8\\b"  << "\\buint16\\b"
                      << "\\buint32\\b" << "\\buint64\\b"  << "\\bint8\\b"
                      << "\\bint16\\b" << "\\bint32\\b" << "\\bint64\\b"
                      << "\\bfloat32\\b" << "\\bfloat64\\b" << "\\bcomplex64\\b"
                      << "\\bcomplex128\\b" << "\\bbyte\\b" << "\\brune\\b"
                      << "\\buint\\b" << "\\bint\\b" << "\\buintptr\\b"
                      << "\\btrue\\b" << "\\bfalse\\b" << "\\bstring\\b";
  foreach(const QString & pattern, keywordPatterns) {
    rule.pattern = QRegExp(pattern);
    rule.format = keywordFormat;
    highlightingRules.append(rule);
  }

  classFormat.setFontWeight(QFont::Bold);
  classFormat.setForeground(Qt::darkMagenta);
  rule.pattern = QRegExp("\\b[A-Za-z]+(?=\\.)");
  rule.format = classFormat;
  highlightingRules.append(rule);

  functionFormat.setFontItalic(true);
  functionFormat.setForeground(Qt::blue);
  rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()");
  rule.format = functionFormat;
  highlightingRules.append(rule);

  quotationFormat.setForeground(Qt::darkGreen);
  rule.pattern = QRegExp("(\"|`).*(\"|`)");
  rule.format = quotationFormat;
  highlightingRules.append(rule);

  singleLineCommentFormat.setForeground(Qt::red);
  rule.pattern = QRegExp("//[^\n]*");
  rule.format = singleLineCommentFormat;
  highlightingRules.append(rule);

  multiLineCommentFormat.setForeground(Qt::red);
  commentStartExpression = QRegExp("/\\*");
  commentEndExpression = QRegExp("\\*/");

  stringFormat.setForeground(Qt::darkGreen);
  stringStartExpression = QRegExp("\\b`");
  stringEndExpression = QRegExp("`\\b");
}

void Highlighter::highlightBlock(const QString &text) {
  foreach(const HighlightingRule & rule, highlightingRules) {
    QRegExp expression(rule.pattern);
    int index = expression.indexIn(text);

    while (index >= 0) {
      int length = expression.matchedLength();
      setFormat(index, length, rule.format);
      index = expression.indexIn(text, index + length);
    }
  }
  setCurrentBlockState(0);
  int startIndex = 0;

  if (previousBlockState() != 1) {
    startIndex = commentStartExpression.indexIn(text);
  }

  while (startIndex >= 0) {
    int endIndex = commentEndExpression.indexIn(text, startIndex);
    int commentLength;

    if (endIndex == -1) {
      setCurrentBlockState(1);
      commentLength = text.length() - startIndex;
    } else {
      commentLength = endIndex - startIndex
                      + commentEndExpression.matchedLength();
    }

    setFormat(startIndex, commentLength, multiLineCommentFormat);
    startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
  }
}
